#pragma once
#include <iostream>
#include <string>
#include <thread>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <cstring>
#include <functional>
#include "Log.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"
#include "Init.hpp"
extern Log lg;
Init dict;
enum
{
    USAGE_ERR = 1,
    SOCKET_ERR,
    BIND_ERR,
    LISTEN_ERR
};


// //echo服务器
// void ServerIo(int sockfd, const std::string &ip, const uint16_t &port)
// {

//     char buffer[4096];
//     // while (true)
//     {
//         ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
//         if (n > 0)
//         {
//             buffer[n] = 0;
//             std::string response = "server echo$ ";
//             response += buffer;
//             send(sockfd, response.c_str(), response.size(), 0);
//         }
//         else if (n == 0)
//         {
//             lg(Info, "%s-%d quit", ip.c_str(), port);
//             // break;
//         }
//         else
//         {
//             lg(Warning, "read err, err: %d, errstring: %s", errno, strerror(errno));
//             // break;
//         }
//     }
//     close(sockfd);
// }

//翻译
void ServerIo(int sockfd, const std::string &ip, const uint16_t &port)
{

    char buffer[4096];
    // while (true)
    {
        ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client key: " << buffer << std::endl;
            std::string response = dict.Translate(buffer);
            // std::cout << "sleep ..." << std::endl;
            // sleep(5);
            // lg(Debug, "write begin");
            n = write(sockfd, response.c_str(), response.size());
            // lg(Debug, "write end");
            if(n < 0)
            {
                lg(Warning, "write error, errno : %d, errstring: %s", errno, strerror(errno));
            }
        }
        else if (n == 0)
        {
            lg(Info, "%s-%d quit", ip.c_str(), port);
            // break;
        }
        else
        {
            lg(Warning, "read err, err: %d, errstring: %s", errno, strerror(errno));
            // break;
        }
    }
    close(sockfd);
}
class TcpServer
{
public:
    TcpServer(const uint16_t port)
        : listensock_(-1), port_(port)
    {
    }
    void InitServer()
    {
        // socket
        listensock_ = socket(PF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            lg(Fatal, "socket create err, listensock_: %d", listensock_);
            exit(SOCKET_ERR);
        }
        lg(Info, "socket create success, listensock_: %d", listensock_);
        int opt = 1;
        setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt));
        // bind
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = INADDR_ANY;
        server.sin_port = htons(port_);
        socklen_t len = sizeof(server);
        if (bind(listensock_, (sockaddr *)&server, len) != 0)
        {
            lg(Fatal, "bind err, err: %d, errstring: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind success, err: %d, errstring: %s", errno, strerror(errno));

        // 设置监听状态
        if (listen(listensock_, 5) != 0)
        {
            lg(Fatal, "listen err, err: %d, errstring: %s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
        lg(Info, "listen success, err: %d, errstring: %s", errno, strerror(errno));
    }
    void Run()
    {
        dict.Load();
        dict.Print();
        signal(SIGPIPE, SIG_IGN);
        ThreadPool<Task>::GetThreadPool()->Run();
        signal(SIGCHLD, SIG_IGN);
        for (;;)
        {
            // accept
            sockaddr_in client;
            socklen_t len = sizeof(client);
            // lg(Debug, "accept begin");
            int sockfd = accept(listensock_, (struct sockaddr *)&client, &len);
            // lg(Debug, "accept end");
            if (sockfd < 0)
            {
                lg(Warning, "accept err, err: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            char clientip[32];
            inet_ntop(AF_INET, &client.sin_addr, clientip, sizeof(clientip));
            uint16_t clientport = ntohs(client.sin_port);
            lg(Info, "accept successs, get a sock: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);

            // //version 1: signal
            // pid_t id = fork();
            // if(id == 0) //child
            // {
            //     close(listensock_);

            //     //version 2: 孙子进程
            //     if(fork() == 0)
            //         ServerIo(sockfd, clientip, clientport);
            //     close(sockfd);
            //     exit(0);
            // }

            // //parent
            // close(sockfd);
            // pid_t rid = waitpid(id, nullptr, 0);

            // // version 3: 多线程
            // std::thread td(ServerIo, sockfd, clientip, clientport);
            // td.detach();


            // version 4: 线程池
            Task t(ServerIo, sockfd, clientip, clientport);
            ThreadPool<Task>::GetThreadPool()->Push(t);
        }
    }

private:
    int listensock_;
    uint16_t port_;
};